import json
from decimal import Decimal
from django import http
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db import transaction
from django.shortcuts import render

# Create your views here.
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection

from apps.goods.models import SKU
from apps.orders.models import OrderInfo, OrderGoods
from apps.users.models import Address
from utils.response_code import RETCODE

'''
    1.这个页面必须是登陆用户可以访问
    2.地址数据的获取
    3.列表数据的获取
        3.1 连接redis
        3.2 hash
            set
        3.3 对bytes数据转换的同时我们重新组织选中的数据
           {sku_id:count}

        3.4 查询商品的详细信息
        3.5 在遍历过程中统计总金额,总数量等信息
'''


# 结算订单
class OrderSettlementView(LoginRequiredMixin, View):
    def get(self, request):
        user = request.user
        try:
            addresses = Address.objects.filter(user=user, is_deleted=False)
        except Address.DoesNotExist:
            addresses = None
        redis_conn = get_redis_connection('carts')
        redis_cart = redis_conn.hgetall('carts:%s' % user.id)
        redis_selected = redis_conn.smembers('selected:%s' % user.id)
        carts = {}
        for sku_id in redis_selected:
            carts[int(sku_id)] = int(redis_cart[sku_id])
        ids = carts.keys()
        # 查询商品的详细信息
        skus = SKU.objects.filter(id__in=ids)

        total_count = 0
        total_among = 0

        for sku in skus:
            sku.count = carts[sku.id]
            sku.among = sku.count * sku.price
            total_count += sku.count
            total_among += sku.among

        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count': total_count,
            'total_among': total_among,
            'freight': 10,
            'payment_amount': total_among + 10
        }

        return render(request, 'place_order.html', context=context)


# 提交订单逻辑
'''
    接收数据
    验证数据
    数据入库
        1订单信息 OrderInfo
            1.1 组织user
            1.2 组织地址信息
            1.3 组织order_id
            1.4 组织总金额 0,运费,总数量 0
            1.5 支付方式
            1.6 订单状态

        2订单商品信息 OrderGoods
            2.1 连接redis,获取redis数据
            2.2 将获取的数据进行类型转换,重新组织选中的数据
                {sku_id:count,sku_id:count}

            2.3 对我们的商品进行遍历
                2.4 判断商品库存是否充足
                2.5 充足则售卖,销量增加,库存减少
                2.6 保存订单商品信息

                2.7 对总金额和总数量进行累加

        3.更新的订单信息(总金额和总数量)

    返回相应

'''


# 提交订单
class OrderCommitView(View):
    def post(self, request):
        data = json.loads(request.body.decode())
        address_id = data.get('address_id')
        pay_method = data.get('pay_method')
        # 校验数据
        if not all([address_id, pay_method]):
            return http.JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '缺少参数'})
        try:
            address = Address.objects.get(id=address_id)
        except Exception:
            return http.JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '参数address_id错误'})
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '参数pay_method错误'})

        # 获取登录用户
        user = request.user
        order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)
        total_amount = Decimal('0')
        total_count = 0
        freight = Decimal('10')
        # 订单状态
        if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH']:
            status = OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        else:
            status = OrderInfo.ORDER_STATUS_ENUM['UNPAID']

        with transaction.atomic():
            # 创建保存点
            save_id = transaction.savepoint()

            # 保存订单基本信息
            order = OrderInfo.objects.create(
                order_id=order_id,
                user=user,
                address=address,
                total_count=total_count,
                total_amount=total_amount,
                freight=freight,
                status=status,
                pay_method=pay_method
            )

            redis_conn = get_redis_connection('carts')
            redis_cart = redis_conn.hgetall('carts:%s' % user.id)
            redis_selected = redis_conn.smemebers('selected:%s' % user.id)
            carts = {}
            for sku_id in redis_selected:
                carts[int(sku_id)] = int(redis_cart[sku_id])

            sku_ids = carts.keys()
            for id in sku_ids:
                sku = SKU.objects.get(id=id)
                sku_count = carts[sku.id]
                if sku_count > sku.stock:
                    # 回滚到保存点
                    transaction.savepoint_rollback(save_id)
                    return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})
                sku.stock -= sku_count
                sku.sales += sku_count
                sku.save()
                # 乐观锁更新库存和销量
                old_stock = sku.stock
                new_stock = sku.stock - sku_count
                new_sales = sku.sales + sku_count
                rect = SKU.objects.filter(stock=old_stock, pk=sku.id).update(stock=new_stock, sales=new_sales)
                if rect == 0:
                    transaction.savepoint_rollback(save_id)
                    return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})
                # 保存订单商品信息
                OrderGoods.objects.create(
                    order=order,
                    sku=sku,
                    count=sku_count,
                    price=sku.price,
                )
                # 对总数量和总金额进行累加
                order.total_count += sku_count
                order.total_amount += (sku.count * sku.price)
            order.total_amount += order.freight
            order.save()
            # 提交从保存点到当前状态的所有数据库失误操作
            transaction.savepoint_commit(save_id)

        pipeline = redis_conn.pipeline()
        pipeline.hdel('carts:%s' % user.id)
        pipeline.srem('selected:%s' % user.id)
        pipeline.execute()
        return http.JsonResponse(
            {'code': RETCODE.OK, 'errmsg': '下单成功', 'order_id': order.order_id, 'payment_amount': order.total_amount})

# 展示提交订单成功页面
class OrderSuccessView(LoginRequiredMixin, View):
    def get(self, request):
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get('pay_method')

        context = {
            'order_id': order_id,
            'payment_amount': payment_amount,
            'pay_method': pay_method
        }
        return render(request, 'order_success.html', context=context)
